<<<<<<< HEAD
#include "lcd.h"

/**
  * @brief  lcd显示屏初始化(申请lcd设备资源)
  * @note   gec6818的显示屏(2024.8.23)
  * @param  dev_pathname: lcd设备文件的路径  
  * @retval 成功：返回lcd设备结构体指针
  *         失败：返回NULL
  */
lcd_msg_p LCD_Init(const s8 *dev_pathname)
{
    // 1、申请堆内存空间(lcd设备结构体)
    lcd_msg_p lcd_p = malloc(sizeof(lcd_msg));
    bzero(lcd_p, sizeof(lcd_msg));

    // 2、判断是否申请成功，成功给lcd设备结构体赋值
    if(lcd_p != NULL)
    {
        // a、打开文件(lcd设备文件)(以读写的权限打开)
        lcd_p->fd = open(dev_pathname, O_RDWR);
        if(-1 == lcd_p->fd)
        {
            printf("PROBLEM: open lcd error; REASON: %s; LINE: %d;\n", strerror(errno), __LINE__);
            return NULL;
        }

        // b、申请一块内存大小为800*480*4的虚拟内存空间给lcd设备
        lcd_p->p = mmap (
                            NULL,                   // 默认为NULL，系统会帮你自动分配虚拟内存空间给lcd设备(当然你也可以自己分配，但是需要直到虚拟内存的地址(必须是可用的、足够大的))
                            800*480*4,              // 映射的lcd设备的虚拟内存的大小
                            PROT_READ|PROT_WRITE,   // 虚拟内存的操作权限(此处的权限必须和你的open函数的权限保持一致)
                            MAP_SHARED,             // 这个虚拟内存是否可以让其它进程使用
                            lcd_p->fd,              // open函数打开成功返回的文件描述符
                            0                       // 虚拟内存一开始的位置(指针指向这块内存一开始的位置)
                        );
        if(lcd_p->p == (void*)-1)
        {
            printf("PROBLEM: mmap lcd error; REASON: %s; LINE: %d;\n", strerror(errno), __LINE__);
            return NULL;
        }

        // c、lcd显示屏映射函数返回的虚拟内存的指针的备份
        lcd_p->tmp_p = NULL;

    }

    // 3、成功返回指向这个lcd设备结构体的指针
    return lcd_p;

}

/**
  * @brief  释放lcd设备资源
  * @note   None
  * @param  lcd_p: 指向lcd设备结构体的指针
  * @retval None
  */
void LCD_UnInit(lcd_msg_p lcd_p)
{
    munmap(lcd_p->p, 800*480*4);    // 解除lcd设备的虚拟内存空间的映射
    close(lcd_p->fd);               // 关闭lcd设备文件
    free(lcd_p);                    // 释放掉lcd设备结构体堆内存空间
}

/**
  * @brief  pic结构体初始化
  * @note   None
  * @param  pic_fomat: 图片的格式
  * @retval 成功：返回pic结构体的指针
  *         失败：返回NULL
  */
pic_msg_p PIC_Init(u8 pic_fomat)
{
    // 1、申请堆内存空间(pic结构体)
    pic_msg_p pic_p = malloc(sizeof(pic_msg));
    bzero(pic_p, sizeof(pic_msg));

    // 2、判断是否申请成功，成功给pic结构体赋值
    if(pic_p != NULL)
    {
        pic_p->     fd  = -1;
        pic_p->format   = pic_fomat;
        pic_p->bmp_buf  = NULL;
        pic_p->tmp_buf  = NULL;
        pic_p->lcd_buf  = NULL;

        bzero(&pic_p->header, sizeof(pic_p->header)); 
        bzero(&pic_p->info, sizeof(pic_p->info)); 

    }

    // 3、成功返回指向这个pic结构体的指针
    return pic_p;

}

/**
  * @brief  释放pic结构体资源
  * @note   None
  * @param  pic_p: 指向pic结构体的指针
  * @retval None
  */
void PIC_UnInit(pic_msg_p pic_p)
{
    bzero(&pic_p->header, sizeof(pic_p->header)); 
    bzero(&pic_p->info, sizeof(pic_p->info)); 
    pic_p->format = NONE_FORMAT;
    close(pic_p->fd);               // 关闭pic文件
    free(pic_p);                    // 释放掉pic结构体堆内存空间
}


/**
  * @brief  显示颜色
  * @note   任意颜色、位置、大小显示在lcd屏幕上
  * @param  lcd_p: 指向lcd设备结构体的指针
  *         color: 要显示的颜色(0x00ff0000(ARGB))
  *         color_w: 要显示颜色块的横轴(宽)
  *         color_h: 要显示颜色块的纵轴(高)
  *         lcd_x: 要现在在lcd屏幕上的x轴的位置
  *         lcd_y: 要现在在lcd屏幕上的y轴的位置
  * @retval None
  */
void LCD_ShowColor(lcd_msg_p lcd_p, u32 color, u16 color_w, u16 color_h, u16 lcd_x, u16 lcd_y)
{
    // 1、记住指向lcd虚拟内存的指针
    lcd_p->tmp_p = lcd_p->p;

    // 2、指针颜色块在lcd显示屏上显示的位置
    lcd_p->p = lcd_p->p + lcd_x;        // x轴
    lcd_p->p = lcd_p->p + lcd_y*800;    // y轴

    // 3、操作指针lcd_p->p(笔)，来对lcd屏幕(虚拟内存)(画板)，写入颜色数据
    int i = 0;
    int j = 0;
    for (i = 0; i < color_w; i++)
    {
        for (j = 0; j < color_h; j++)
        {
           *(lcd_p->p+j*800+i)  = color;
        }    
    }
    
    // 4、重新指针lcd虚拟内存的首地址
    lcd_p->p = lcd_p->tmp_p;
}

/**
  * @brief  显示图片
  * @note   任意的图片、位置、大小显示在lcd屏幕上
  * @param  lcd_p: 指向lcd设备结构体的指针
  *         pic_p: 指向pic结构体的指针
  *         
  *         lcd_x: 要现在在lcd屏幕上的x轴的位置
  *         lcd_y: 要现在在lcd屏幕上的y轴的位置
  * @retval None
  */
void LCD_ShowPicture(lcd_msg_p lcd_p, pic_msg_p pic_p,  const u8* pic_path, u16 lcd_x, u16 lcd_y, u8 show_effect)
{
    switch (pic_p->format)
    {
        case BMP_FORMAT:
    
            // 零、记住最初的位置
           // int (*p)[800] = (int (*)[800])lcd_p->p;

            // 一、获取bmp图片的信息(第一部分：54个字节的头信息)
            // 1、打开文件(bmp图片文件)
            pic_p->fd =  open(pic_path, O_RDONLY);
            if (-1 == pic_p->fd)
            {
                printf("PROBLEM: open bmp error; REASON: %s; LINE: %d;\n", strerror(errno), __LINE__);
                return;
            }

            // 2、读取bmp图片的54个头信息数据
            read(pic_p->fd, &pic_p->header, sizeof(pic_p->header));
            read(pic_p->fd, &pic_p->info, sizeof(pic_p->info));

            int bmp_w = pic_p->info.width;     
            int bmp_h = pic_p->info.height;

            // printf("图片的宽为： %d字节\n", bmp_w);
            // printf("图片的高为： %d字节\n", bmp_h);

            // 3、判断图片是否超出屏幕显示
            if(bmp_w+lcd_x>800 || bmp_h+lcd_y>480)
            {
                printf("图片显示超出屏幕, 请正确显示!\n");
            }

            // 二、获取bmp图片的数据(第二部分：BGR的颜色数据)
            // 1、略过图片的54个头信息数据
            lseek(pic_p->fd, 54, SEEK_SET);

            // 2、读取bmp图片的第二部分的数据(BGR)
            pic_p->bmp_buf = malloc(bmp_w*bmp_h*3);
            read(pic_p->fd, pic_p->bmp_buf, bmp_w*bmp_h*3);

            // 3、关闭文件
            close(pic_p->fd);

            // 三、将获取的bmp图片的数据(BGR)，转换为可以显示在lcd屏幕上的lcd数据(ARGB)
            int x = 0;
            int y = 0;
            int j = 0;
            int k = 0;
            int i = 0;

            // 1、转换数据
            pic_p->lcd_buf = malloc(bmp_w*bmp_h*4);
            pic_p->tmp_buf = malloc(bmp_w*bmp_h*4);
            for (i = 0; i < bmp_w*bmp_h; i++)
            {
                pic_p->tmp_buf[i]  =  (pic_p->bmp_buf[i*3]<<0) + (pic_p->bmp_buf[i*3+1]<<8) + (pic_p->bmp_buf[i*3+2]<<16) + (0x00<<24);
                // ARGB                                  B                        G                             R                          A
            }
            
            
            // 2、正转lcd数据
            for(y=0; y<bmp_h; y++)
            {
                for(x=0; x<bmp_w; x++)
                {
                    *(pic_p->lcd_buf+y*bmp_w+x) =  pic_p->tmp_buf[(bmp_h-1-y)*bmp_w+x];		
                }
            }


            // 四、将转换后的的lcd数据(ARGB)，写入到lcd屏幕文件上
            // 1、记住指向lcd虚拟内存的指针
            lcd_p->tmp_p = lcd_p->p;

            // 2、指针颜色块在lcd显示屏上显示的位置
            lcd_p->p = lcd_p->p + lcd_x;        // x轴
            lcd_p->p = lcd_p->p + lcd_y*800;    // y轴

            // 3、操作指针lcd_p->p(笔)，来对lcd屏幕(虚拟内存)(画板)，写入颜色数据
            x = 0;
            y = 0;
            j = 0;
            k = 0;
            i = 0;

            switch (show_effect)
            {
                case 0:     // 正常显示
                    for ( y = 0; y < bmp_h; y++)
                    {
                        for (x = 0; x < bmp_w; x++)
                        {
                            *(lcd_p->p+800*y+x) = pic_p->lcd_buf[bmp_w*y+x];
                        }
                        
                    }
                    break;

                case 1:     // 从上到下
                    for(y=0;y<bmp_h;y++)
                    {
                        for(x=0;x<bmp_w;x++)
                        {		
                            *(lcd_p->p+800*y+x)= pic_p->lcd_buf[bmp_w*y+x];
                        }
                        usleep(3000);//停顿3毫秒，让我们能够观察到图片是如何在LCD上面显示出来的
                    }
	
                case 2:		//从下到上：
                    for(y=0;y<bmp_h;y++)
                    {
                        for(x=0;x<bmp_w;x++)
                        {		
                            *(lcd_p->p+800*(bmp_h-y-1)+x) = pic_p->lcd_buf[(bmp_h-y-1)*bmp_w+x];
                        }
                        usleep(3000);//停顿3毫秒，让我们能够观察到图片是如何在LCD上面显示出来的
                    }
                    break;

                case 3:		//从左往右
                    for(x=0;x<bmp_w;x++)
			        {
				        for(y=0;y<bmp_h;y++)
                        {		
                           *(lcd_p->p+800*y+x)= pic_p->lcd_buf[y*bmp_w+x];
                        }
                        usleep(2000);//停顿2毫秒，让我们能够观察到图片是如何在LCD上面显示出来的
                    }
                    break;
		
                case 4:		//从右到左：
                    for(x=0; x<bmp_w; x++)
                    {
                        for(y=0; y<bmp_h; y++)
                        {		
                            *(lcd_p->p+800*y+bmp_w-x-1)= pic_p->lcd_buf[y*bmp_w+bmp_w-x-1];
                        }							
                        usleep(2000);//时间停顿，显示刷的效果				
                    }
                    break;
		
                case 5:		// 竖百叶窗
                    for(x=0;x<(bmp_w/8);x++)
                    {
                        for(y=0;y<bmp_h;y++)
                        {
                            for(k=0;k<8;k++)
                            {
                                *(lcd_p->p+800*y+x+k*bmp_w/8) = pic_p->lcd_buf[y*bmp_w+x+k*bmp_w/8];
                            }
                        }
                        usleep(4000);			
                    }
                    break;
			
                case 6:		// 横百叶窗
                    for(y=0;y<(bmp_h/8);y++)
                    {
                        for(x=0;x<bmp_w;x++)
                        {
                            for(k=0;k<8;k++)
                            {
                                *(lcd_p->p+800*(y+k*bmp_h/8)+x) = pic_p->tmp_buf[(bmp_h-1-y-k*bmp_h/8)*bmp_w+x];
                            }
                        }
                        usleep(3000);			
                    }
                    break;
		
                case 7:		// 圆形收缩
                    for(k=bmp_h*975/1000;k>=0;k-=3)
                    {
                        for(y=0;y<bmp_h;y++)
                        {
                            for(x=0;x<bmp_w;x++)
                            {
                                if((x-bmp_w/2)*(x-bmp_w/2)+(y-bmp_h/2)*(y-bmp_h/2)>=k*k)
                                {
                                    *(lcd_p->p+800*y+x) = pic_p->lcd_buf[y*bmp_w+x];
                                }
                            }
                        }
                        usleep(500);
                    }
                    break;
	
                case 8:		// 圆形扩散
                    for(k=0;k<(bmp_h*975/1000);k+=3)
                    {
                        for(y=0;y<bmp_h;y++)
                        {
                            for(x=0;x<bmp_w;x++)
                            {
                                if((x-bmp_w/2)*(x-bmp_w/2)+(y-bmp_h/2)*(y-bmp_h/2)<=k*k)
                                {
                                    *(lcd_p->p+800*y+x) = pic_p->lcd_buf[y*bmp_w+x];
                                }
                            }
                        }
                        usleep(500);
                    }   
                    break;

                case 9:	 // 从左往右移动
                    for ( i = bmp_w; i>0; i--)
                    {
                        for(y=0;y<bmp_h;y++)
                        {
                            for(x=0;x<bmp_w-i;x++)
                            {   
                                *(lcd_p->p+y*800+x) = pic_p->lcd_buf[y*bmp_w+i+x]; 
                            }
                        }
                        lcd_p->p = lcd_p->tmp_p;
                        lcd_p->p = lcd_p->p + lcd_x;        // x轴
                        lcd_p->p = lcd_p->p + lcd_y*800;    // y轴
                        usleep(100);
                    }
			        break;

                case 10: // 从右往左移动
                    for ( i = bmp_w; i>0; i--)
                    {
                        for(y=0;y<bmp_h;y++)
                        {
                            for(x=0;x<bmp_w-i;x++)
                            {   
                                *(lcd_p->p+y*800+x+i) = pic_p->lcd_buf[y*bmp_w+x]; 
                            }
                        }
                        lcd_p->p = lcd_p->tmp_p;
                        lcd_p->p = lcd_p->p + lcd_x;        // x轴
                        lcd_p->p = lcd_p->p + lcd_y*800;    // y轴
                        usleep(100);
                    }
                    break;
			
                case 11: // 从上到下移动
                    for ( i = bmp_h; i>0; i--)
                    {
                        for(y=0;y<bmp_h-i;y++)
                        {
                            for(x=0;x<bmp_w;x++)
                            {   
                                *(lcd_p->p+y*800+x) = pic_p->lcd_buf[(y+i)*bmp_w+x]; 
                            }
                        }
                        lcd_p->p = lcd_p->tmp_p;
                        lcd_p->p = lcd_p->p + lcd_x;        // x轴
                        lcd_p->p = lcd_p->p + lcd_y*800;    // y轴
                        usleep(100);
                    }
                    break;

                case 12: // 从下到上移动
                    for ( i = bmp_h; i>0; i--)
                    {
                        for(y=0;y<bmp_h-i;y++)
                        {
                            for(x=0;x<bmp_w;x++)
                            {   
                                *(lcd_p->p+(y+i)*800+x) = pic_p->lcd_buf[y*bmp_w+x]; 
                            }
                        }
                        lcd_p->p = lcd_p->tmp_p;
                        lcd_p->p = lcd_p->p + lcd_x;        // x轴
                        lcd_p->p = lcd_p->p + lcd_y*800;    // y轴
                        usleep(100);
                    }
                    break;


            }

        
            // 4、重新指针lcd虚拟内存的首地址
            lcd_p->p = lcd_p->tmp_p;
            
            // 5、释放内存
            free(pic_p->bmp_buf);
            free(pic_p->lcd_buf);
            free(pic_p->tmp_buf);

            break;
            
        case JPG_FORMAT:
            printf("你还没有编写jpg图片的功能!!\n");
            break;

        case PNG_FORMAT:
            printf("你还没有编写png图片的功能!!\n");
            break;  

    }
}

/**
  * @brief  显示字到开发板屏幕上
  * @note   None
  * @param  lcd：			显示屏的结构体指针
			f_s：			字体大小
			bm_w：			画板的宽
			bm_h：			画板的高
			bm_c：			画板的颜色
			f_x：			字体在画板的x轴位置
			f_y： 			字体在画板的y轴位置
			buf：			需要显示的字
			f_c： 			字体的颜色
			f_lw：			字体显示在行的宽度，超过则换行，一般写0，默认不换行
			lcd_x：			画板和字形成的bmp图片，在显示屏的x轴的显示位置
			lcd_y：			画板和字形成的bmp图片，在显示屏的y轴的显示位置
			lcd_effect：	画板和字形成的bmp图片，在显示屏的显示效果
  * @retval None
 */

void LCD_ShowColorFont(lcd_msg_p lcd, int f_s, int bm_w, int bm_h, color bm_c, int f_x, int f_y, char *font_text, color f_c, int f_lw, int lcd_x, int lcd_y)
{
	// 1、打开字体	
	font *f = fontLoad("/usr/share/fonts/DroidSansFallback.ttf");

	// 2、字体大小的设置
	fontSetSize(f, f_s);

	// 3、创建一个画板（点阵图）
	bitmap *bm = createBitmapWithInit(bm_w, bm_h, 4, bm_c); 
																// A, R, G, B，画板的颜色
	// 4、将字写到画板(点阵图)上，形成一张bmp图片
	fontPrint(f, bm, f_x, f_y, font_text, f_c, f_lw); 
										   // A, R, G, B，字的颜色
	// 5、将形成的bmp图片，显示到开发板lcd设备上
	// a、记住最初的位置
	int (*p)[800] = (int (*)[800])lcd->p;
	
	// b、判断要刷的图片是否超过了屏幕范围
	int   w       = bm->width;
	int   h       = bm->height;
	int   n       = bm->byteperpixel;
	unsigned char *bmp_buf = bm->map;

	if(w+lcd_x>800 || h+lcd_y>480)
	{
		printf("bmp图片越界!\n");
        return;
	}
	
	// c、将获取的BGR数据(bmp的颜色数据)，转换成ARGB数据(lcd数据)
	unsigned int tmp_buf[w*h];				// ARGB数据(lcd数据)存放地(变长数组，不能赋值)
	unsigned int lcd_buf[w*h];				// ARGB数据(lcd数据)存放地(变长数组，不能赋值)
	
	int i,j,k,x,y;
	
	// 正的的lcd数据
	for(i=0; i<w*h; i++)
	{
		tmp_buf[i] = (bmp_buf[i*4+0]<<16) | (bmp_buf[i*4+1]<<8) | (bmp_buf[i*4+2]<<0) | (bmp_buf[i*4+3]<<24);
		//ARGB            R                     G                      B                 A
	}  
	
	// 上下翻转颠倒的lcd数据
	for(y=0; y<h; y++)
	{
		for(x=0; x<w; x++)
		{
			lcd_buf[y*w+x] = tmp_buf[(h-1-y)*w+x];				// (二维数组) 
	     
	    }
	}
	
	// d、显示bmp图片到lcd设备上
    for(y=0;y<h;y++)
    {
        for(x=0;x<w;x++)
        {		
            p[y+lcd_y][x+lcd_x]= lcd_buf[(h-1-y)*w+x];;

        }
    }

	// 6、关闭字库、画板
	fontUnload(f);
	destroyBitmap(bm);
}
/**
  * @brief  显示字到开发板屏幕上
  * @note   None
  * @param  lcd：			显示屏的结构体指针
			f_s：			字体大小
			bmp_buf：		bmp图片路径
			f_x：			字体在bmp的x轴位置
			f_y： 			字体在bmp的y轴位置
			font_text：		需要显示的字
			f_c： 			字体的颜色
			f_lw：			字体显示在行的宽度，超过则换行，一般写0，默认不换行
			lcd_x：			画板和字形成的bmp图片，在显示屏的x轴的显示位置
			lcd_y：			画板和字形成的bmp图片，在显示屏的y轴的显示位置
  * @retval None
 */
void LCD_ShowPicFont(lcd_msg *lcd, int f_s, char *bmp_path, int f_x, int f_y, char *font_text, color f_c, int f_lw, int lcd_x, int lcd_y)
{
	// 1、打开字体	
	font *f = fontLoad("/usr/share/fonts/DroidSansFallback.ttf");

	// 2、字体大小的设置
	fontSetSize(f, f_s);

	// 3、创建一个画板（点阵图）
	bitmap *bm = createBitmapWithInit_bmp(bmp_path);
	
																// A, R, G, B，画板的颜色
	// 4、将字写到画板(点阵图)上，形成一张bmp图片
	fontPrint(f, bm, f_x, f_y, font_text, f_c, f_lw); 
										   // A, R, G, B，字的颜色
	// 5、将形成的bmp图片，显示到开发板lcd设备上
    // Lcd_ShowFontBmpToLcd(lcd, bm, lcd_x, lcd_y);	
	// a、记住最初的位置
	int (*p)[800] = (int (*)[800])lcd->p;
	
	// b、判断要刷的图片是否超过了屏幕范围
	int   w       = bm->width;
	int   h       = bm->height;
	int   n       = bm->byteperpixel;
	unsigned char *bmp_buf = bm->map;

	if(w+lcd_x>800 || h+lcd_y>480)
	{
		printf("bmp图片越界!\n");
		return;
	}
	
	// c、将获取的BGR数据(bmp的颜色数据)，转换成ARGB数据(lcd数据)
	unsigned int tmp_buf[w*h];				// ARGB数据(lcd数据)存放地(变长数组，不能赋值)
	unsigned int lcd_buf[w*h];				// ARGB数据(lcd数据)存放地(变长数组，不能赋值)
	
	int i,j,k,x,y;
	
	// 正的的lcd数据
	for(i=0; i<w*h; i++)
	{
		tmp_buf[i] = (bmp_buf[i*4+0]<<16) | (bmp_buf[i*4+1]<<8) | (bmp_buf[i*4+2]<<0) | (bmp_buf[i*4+3]<<24);
		//ARGB            R                     G                      B                 A
	}  
	
	// 上下翻转颠倒的lcd数据
	for(y=0; y<h; y++)
	{
		for(x=0; x<w; x++)
		{
			lcd_buf[y*w+x] = tmp_buf[(h-1-y)*w+x];				// (二维数组) 
	     
	    }
	}
	
	// d、显示bmp图片到lcd设备上
    for(y=0;y<h;y++)
    {
        for(x=0;x<w;x++)
        {		
            p[y+lcd_y][x+lcd_x]= lcd_buf[(h-1-y)*w+x];;

        }
    }
	
	// 6、关闭字库、画板
	fontUnload(f);
	destroyBitmap(bm);
}
=======
#include "lcd.h"

/**
  * @brief  lcd显示屏初始化(申请lcd设备资源)
  * @note   gec6818的显示屏(2024.8.23)
  * @param  dev_pathname: lcd设备文件的路径  
  * @retval 成功：返回lcd设备结构体指针
  *         失败：返回NULL
  */
lcd_msg_p LCD_Init(const s8 *dev_pathname)
{
    // 1、申请堆内存空间(lcd设备结构体)
    lcd_msg_p lcd_p = malloc(sizeof(lcd_msg));
    bzero(lcd_p, sizeof(lcd_msg));

    // 2、判断是否申请成功，成功给lcd设备结构体赋值
    if(lcd_p != NULL)
    {
        // a、打开文件(lcd设备文件)(以读写的权限打开)
        lcd_p->fd = open(dev_pathname, O_RDWR);
        if(-1 == lcd_p->fd)
        {
            printf("PROBLEM: open lcd error; REASON: %s; LINE: %d;\n", strerror(errno), __LINE__);
            return NULL;
        }

        // b、申请一块内存大小为800*480*4的虚拟内存空间给lcd设备
        lcd_p->p = mmap (
                            NULL,                   // 默认为NULL，系统会帮你自动分配虚拟内存空间给lcd设备(当然你也可以自己分配，但是需要直到虚拟内存的地址(必须是可用的、足够大的))
                            800*480*4,              // 映射的lcd设备的虚拟内存的大小
                            PROT_READ|PROT_WRITE,   // 虚拟内存的操作权限(此处的权限必须和你的open函数的权限保持一致)
                            MAP_SHARED,             // 这个虚拟内存是否可以让其它进程使用
                            lcd_p->fd,              // open函数打开成功返回的文件描述符
                            0                       // 虚拟内存一开始的位置(指针指向这块内存一开始的位置)
                        );
        if(lcd_p->p == (void*)-1)
        {
            printf("PROBLEM: mmap lcd error; REASON: %s; LINE: %d;\n", strerror(errno), __LINE__);
            return NULL;
        }

        // c、lcd显示屏映射函数返回的虚拟内存的指针的备份
        lcd_p->tmp_p = NULL;

    }

    // 3、成功返回指向这个lcd设备结构体的指针
    return lcd_p;

}

/**
  * @brief  释放lcd设备资源
  * @note   None
  * @param  lcd_p: 指向lcd设备结构体的指针
  * @retval None
  */
void LCD_UnInit(lcd_msg_p lcd_p)
{
    munmap(lcd_p->p, 800*480*4);    // 解除lcd设备的虚拟内存空间的映射
    close(lcd_p->fd);               // 关闭lcd设备文件
    free(lcd_p);                    // 释放掉lcd设备结构体堆内存空间
}

/**
  * @brief  pic结构体初始化
  * @note   None
  * @param  pic_fomat: 图片的格式
  * @retval 成功：返回pic结构体的指针
  *         失败：返回NULL
  */
pic_msg_p PIC_Init(u8 pic_fomat)
{
    // 1、申请堆内存空间(pic结构体)
    pic_msg_p pic_p = malloc(sizeof(pic_msg));
    bzero(pic_p, sizeof(pic_msg));

    // 2、判断是否申请成功，成功给pic结构体赋值
    if(pic_p != NULL)
    {
        pic_p->     fd  = -1;
        pic_p->format   = pic_fomat;
        pic_p->bmp_buf  = NULL;
        pic_p->tmp_buf  = NULL;
        pic_p->lcd_buf  = NULL;

        bzero(&pic_p->header, sizeof(pic_p->header)); 
        bzero(&pic_p->info, sizeof(pic_p->info)); 

    }

    // 3、成功返回指向这个pic结构体的指针
    return pic_p;

}

/**
  * @brief  释放pic结构体资源
  * @note   None
  * @param  pic_p: 指向pic结构体的指针
  * @retval None
  */
void PIC_UnInit(pic_msg_p pic_p)
{
    bzero(&pic_p->header, sizeof(pic_p->header)); 
    bzero(&pic_p->info, sizeof(pic_p->info)); 
    pic_p->format = NONE_FORMAT;
    close(pic_p->fd);               // 关闭pic文件
    free(pic_p);                    // 释放掉pic结构体堆内存空间
}


/**
  * @brief  显示颜色
  * @note   任意颜色、位置、大小显示在lcd屏幕上
  * @param  lcd_p: 指向lcd设备结构体的指针
  *         color: 要显示的颜色(0x00ff0000(ARGB))
  *         color_w: 要显示颜色块的横轴(宽)
  *         color_h: 要显示颜色块的纵轴(高)
  *         lcd_x: 要现在在lcd屏幕上的x轴的位置
  *         lcd_y: 要现在在lcd屏幕上的y轴的位置
  * @retval None
  */
void LCD_ShowColor(lcd_msg_p lcd_p, u32 color, u16 color_w, u16 color_h, u16 lcd_x, u16 lcd_y)
{
    // 1、记住指向lcd虚拟内存的指针
    lcd_p->tmp_p = lcd_p->p;

    // 2、指针颜色块在lcd显示屏上显示的位置
    lcd_p->p = lcd_p->p + lcd_x;        // x轴
    lcd_p->p = lcd_p->p + lcd_y*800;    // y轴

    // 3、操作指针lcd_p->p(笔)，来对lcd屏幕(虚拟内存)(画板)，写入颜色数据
    int i = 0;
    int j = 0;
    for (i = 0; i < color_w; i++)
    {
        for (j = 0; j < color_h; j++)
        {
           *(lcd_p->p+j*800+i)  = color;
        }    
    }
    
    // 4、重新指针lcd虚拟内存的首地址
    lcd_p->p = lcd_p->tmp_p;
}

/**
  * @brief  显示图片
  * @note   任意的图片、位置、大小显示在lcd屏幕上
  * @param  lcd_p: 指向lcd设备结构体的指针
  *         pic_p: 指向pic结构体的指针
  *         
  *         lcd_x: 要现在在lcd屏幕上的x轴的位置
  *         lcd_y: 要现在在lcd屏幕上的y轴的位置
  * @retval None
  */
void LCD_ShowPicture(lcd_msg_p lcd_p, pic_msg_p pic_p,  const u8* pic_path, u16 lcd_x, u16 lcd_y, u8 show_effect)
{
    switch (pic_p->format)
    {
        case BMP_FORMAT:
    
            // 零、记住最初的位置
           // int (*p)[800] = (int (*)[800])lcd_p->p;

            // 一、获取bmp图片的信息(第一部分：54个字节的头信息)
            // 1、打开文件(bmp图片文件)
            pic_p->fd =  open(pic_path, O_RDONLY);
            if (-1 == pic_p->fd)
            {
                printf("PROBLEM: open bmp error; REASON: %s; LINE: %d;\n", strerror(errno), __LINE__);
                return;
            }

            // 2、读取bmp图片的54个头信息数据
            read(pic_p->fd, &pic_p->header, sizeof(pic_p->header));
            read(pic_p->fd, &pic_p->info, sizeof(pic_p->info));

            int bmp_w = pic_p->info.width;     
            int bmp_h = pic_p->info.height;

            // printf("图片的宽为： %d字节\n", bmp_w);
            // printf("图片的高为： %d字节\n", bmp_h);

            // 3、判断图片是否超出屏幕显示
            if(bmp_w+lcd_x>800 || bmp_h+lcd_y>480)
            {
                printf("图片显示超出屏幕, 请正确显示!\n");
            }

            // 二、获取bmp图片的数据(第二部分：BGR的颜色数据)
            // 1、略过图片的54个头信息数据
            lseek(pic_p->fd, 54, SEEK_SET);

            // 2、读取bmp图片的第二部分的数据(BGR)
            pic_p->bmp_buf = malloc(bmp_w*bmp_h*3);
            read(pic_p->fd, pic_p->bmp_buf, bmp_w*bmp_h*3);

            // 3、关闭文件
            close(pic_p->fd);

            // 三、将获取的bmp图片的数据(BGR)，转换为可以显示在lcd屏幕上的lcd数据(ARGB)
            int x = 0;
            int y = 0;
            int j = 0;
            int k = 0;
            int i = 0;

            // 1、转换数据
            pic_p->lcd_buf = malloc(bmp_w*bmp_h*4);
            pic_p->tmp_buf = malloc(bmp_w*bmp_h*4);
            for (i = 0; i < bmp_w*bmp_h; i++)
            {
                pic_p->tmp_buf[i]  =  (pic_p->bmp_buf[i*3]<<0) + (pic_p->bmp_buf[i*3+1]<<8) + (pic_p->bmp_buf[i*3+2]<<16) + (0x00<<24);
                // ARGB                                  B                        G                             R                          A
            }
            
            
            // 2、正转lcd数据
            for(y=0; y<bmp_h; y++)
            {
                for(x=0; x<bmp_w; x++)
                {
                    *(pic_p->lcd_buf+y*bmp_w+x) =  pic_p->tmp_buf[(bmp_h-1-y)*bmp_w+x];		
                }
            }


            // 四、将转换后的的lcd数据(ARGB)，写入到lcd屏幕文件上
            // 1、记住指向lcd虚拟内存的指针
            lcd_p->tmp_p = lcd_p->p;

            // 2、指针颜色块在lcd显示屏上显示的位置
            lcd_p->p = lcd_p->p + lcd_x;        // x轴
            lcd_p->p = lcd_p->p + lcd_y*800;    // y轴

            // 3、操作指针lcd_p->p(笔)，来对lcd屏幕(虚拟内存)(画板)，写入颜色数据
            x = 0;
            y = 0;
            j = 0;
            k = 0;
            i = 0;

            switch (show_effect)
            {
                case 0:     // 正常显示
                    for ( y = 0; y < bmp_h; y++)
                    {
                        for (x = 0; x < bmp_w; x++)
                        {
                            *(lcd_p->p+800*y+x) = pic_p->lcd_buf[bmp_w*y+x];
                        }
                        
                    }
                    break;

                case 1:     // 从上到下
                    for(y=0;y<bmp_h;y++)
                    {
                        for(x=0;x<bmp_w;x++)
                        {		
                            *(lcd_p->p+800*y+x)= pic_p->lcd_buf[bmp_w*y+x];
                        }
                        usleep(3000);//停顿3毫秒，让我们能够观察到图片是如何在LCD上面显示出来的
                    }
	
                case 2:		//从下到上：
                    for(y=0;y<bmp_h;y++)
                    {
                        for(x=0;x<bmp_w;x++)
                        {		
                            *(lcd_p->p+800*(bmp_h-y-1)+x) = pic_p->lcd_buf[(bmp_h-y-1)*bmp_w+x];
                        }
                        usleep(3000);//停顿3毫秒，让我们能够观察到图片是如何在LCD上面显示出来的
                    }
                    break;

                case 3:		//从左往右
                    for(x=0;x<bmp_w;x++)
			        {
				        for(y=0;y<bmp_h;y++)
                        {		
                           *(lcd_p->p+800*y+x)= pic_p->lcd_buf[y*bmp_w+x];
                        }
                        usleep(2000);//停顿2毫秒，让我们能够观察到图片是如何在LCD上面显示出来的
                    }
                    break;
		
                case 4:		//从右到左：
                    for(x=0; x<bmp_w; x++)
                    {
                        for(y=0; y<bmp_h; y++)
                        {		
                            *(lcd_p->p+800*y+bmp_w-x-1)= pic_p->lcd_buf[y*bmp_w+bmp_w-x-1];
                        }							
                        usleep(2000);//时间停顿，显示刷的效果				
                    }
                    break;
		
                case 5:		// 竖百叶窗
                    for(x=0;x<(bmp_w/8);x++)
                    {
                        for(y=0;y<bmp_h;y++)
                        {
                            for(k=0;k<8;k++)
                            {
                                *(lcd_p->p+800*y+x+k*bmp_w/8) = pic_p->lcd_buf[y*bmp_w+x+k*bmp_w/8];
                            }
                        }
                        usleep(4000);			
                    }
                    break;
			
                case 6:		// 横百叶窗
                    for(y=0;y<(bmp_h/8);y++)
                    {
                        for(x=0;x<bmp_w;x++)
                        {
                            for(k=0;k<8;k++)
                            {
                                *(lcd_p->p+800*(y+k*bmp_h/8)+x) = pic_p->tmp_buf[(bmp_h-1-y-k*bmp_h/8)*bmp_w+x];
                            }
                        }
                        usleep(3000);			
                    }
                    break;
		
                case 7:		// 圆形收缩
                    for(k=bmp_h*975/1000;k>=0;k-=3)
                    {
                        for(y=0;y<bmp_h;y++)
                        {
                            for(x=0;x<bmp_w;x++)
                            {
                                if((x-bmp_w/2)*(x-bmp_w/2)+(y-bmp_h/2)*(y-bmp_h/2)>=k*k)
                                {
                                    *(lcd_p->p+800*y+x) = pic_p->lcd_buf[y*bmp_w+x];
                                }
                            }
                        }
                        usleep(500);
                    }
                    break;
	
                case 8:		// 圆形扩散
                    for(k=0;k<(bmp_h*975/1000);k+=3)
                    {
                        for(y=0;y<bmp_h;y++)
                        {
                            for(x=0;x<bmp_w;x++)
                            {
                                if((x-bmp_w/2)*(x-bmp_w/2)+(y-bmp_h/2)*(y-bmp_h/2)<=k*k)
                                {
                                    *(lcd_p->p+800*y+x) = pic_p->lcd_buf[y*bmp_w+x];
                                }
                            }
                        }
                        usleep(500);
                    }   
                    break;

                case 9:	 // 从左往右移动
                    for ( i = bmp_w; i>0; i--)
                    {
                        for(y=0;y<bmp_h;y++)
                        {
                            for(x=0;x<bmp_w-i;x++)
                            {   
                                *(lcd_p->p+y*800+x) = pic_p->lcd_buf[y*bmp_w+i+x]; 
                            }
                        }
                        lcd_p->p = lcd_p->tmp_p;
                        lcd_p->p = lcd_p->p + lcd_x;        // x轴
                        lcd_p->p = lcd_p->p + lcd_y*800;    // y轴
                        usleep(100);
                    }
			        break;

                case 10: // 从右往左移动
                    for ( i = bmp_w; i>0; i--)
                    {
                        for(y=0;y<bmp_h;y++)
                        {
                            for(x=0;x<bmp_w-i;x++)
                            {   
                                *(lcd_p->p+y*800+x+i) = pic_p->lcd_buf[y*bmp_w+x]; 
                            }
                        }
                        lcd_p->p = lcd_p->tmp_p;
                        lcd_p->p = lcd_p->p + lcd_x;        // x轴
                        lcd_p->p = lcd_p->p + lcd_y*800;    // y轴
                        usleep(100);
                    }
                    break;
			
                case 11: // 从上到下移动
                    for ( i = bmp_h; i>0; i--)
                    {
                        for(y=0;y<bmp_h-i;y++)
                        {
                            for(x=0;x<bmp_w;x++)
                            {   
                                *(lcd_p->p+y*800+x) = pic_p->lcd_buf[(y+i)*bmp_w+x]; 
                            }
                        }
                        lcd_p->p = lcd_p->tmp_p;
                        lcd_p->p = lcd_p->p + lcd_x;        // x轴
                        lcd_p->p = lcd_p->p + lcd_y*800;    // y轴
                        usleep(100);
                    }
                    break;

                case 12: // 从下到上移动
                    for ( i = bmp_h; i>0; i--)
                    {
                        for(y=0;y<bmp_h-i;y++)
                        {
                            for(x=0;x<bmp_w;x++)
                            {   
                                *(lcd_p->p+(y+i)*800+x) = pic_p->lcd_buf[y*bmp_w+x]; 
                            }
                        }
                        lcd_p->p = lcd_p->tmp_p;
                        lcd_p->p = lcd_p->p + lcd_x;        // x轴
                        lcd_p->p = lcd_p->p + lcd_y*800;    // y轴
                        usleep(100);
                    }
                    break;


            }

        
            // 4、重新指针lcd虚拟内存的首地址
            lcd_p->p = lcd_p->tmp_p;
            
            // 5、释放内存
            free(pic_p->bmp_buf);
            free(pic_p->lcd_buf);
            free(pic_p->tmp_buf);

            break;
            
        case JPG_FORMAT:
            printf("你还没有编写jpg图片的功能!!\n");
            break;

        case PNG_FORMAT:
            printf("你还没有编写png图片的功能!!\n");
            break;  

    }
}

/**
  * @brief  显示字到开发板屏幕上
  * @note   None
  * @param  lcd：			显示屏的结构体指针
			f_s：			字体大小
			bm_w：			画板的宽
			bm_h：			画板的高
			bm_c：			画板的颜色
			f_x：			字体在画板的x轴位置
			f_y： 			字体在画板的y轴位置
			buf：			需要显示的字
			f_c： 			字体的颜色
			f_lw：			字体显示在行的宽度，超过则换行，一般写0，默认不换行
			lcd_x：			画板和字形成的bmp图片，在显示屏的x轴的显示位置
			lcd_y：			画板和字形成的bmp图片，在显示屏的y轴的显示位置
			lcd_effect：	画板和字形成的bmp图片，在显示屏的显示效果
  * @retval None
 */

void LCD_ShowColorFont(lcd_msg_p lcd, int f_s, int bm_w, int bm_h, color bm_c, int f_x, int f_y, char *font_text, color f_c, int f_lw, int lcd_x, int lcd_y)
{
	// 1、打开字体	
	font *f = fontLoad("/usr/share/fonts/DroidSansFallback.ttf");

	// 2、字体大小的设置
	fontSetSize(f, f_s);

	// 3、创建一个画板（点阵图）
	bitmap *bm = createBitmapWithInit(bm_w, bm_h, 4, bm_c); 
																// A, R, G, B，画板的颜色
	// 4、将字写到画板(点阵图)上，形成一张bmp图片
	fontPrint(f, bm, f_x, f_y, font_text, f_c, f_lw); 
										   // A, R, G, B，字的颜色
	// 5、将形成的bmp图片，显示到开发板lcd设备上
	// a、记住最初的位置
	int (*p)[800] = (int (*)[800])lcd->p;
	
	// b、判断要刷的图片是否超过了屏幕范围
	int   w       = bm->width;
	int   h       = bm->height;
	int   n       = bm->byteperpixel;
	unsigned char *bmp_buf = bm->map;

	if(w+lcd_x>800 || h+lcd_y>480)
	{
		printf("bmp图片越界!\n");
        return;
	}
	
	// c、将获取的BGR数据(bmp的颜色数据)，转换成ARGB数据(lcd数据)
	unsigned int tmp_buf[w*h];				// ARGB数据(lcd数据)存放地(变长数组，不能赋值)
	unsigned int lcd_buf[w*h];				// ARGB数据(lcd数据)存放地(变长数组，不能赋值)
	
	int i,j,k,x,y;
	
	// 正的的lcd数据
	for(i=0; i<w*h; i++)
	{
		tmp_buf[i] = (bmp_buf[i*4+0]<<16) | (bmp_buf[i*4+1]<<8) | (bmp_buf[i*4+2]<<0) | (bmp_buf[i*4+3]<<24);
		//ARGB            R                     G                      B                 A
	}  
	
	// 上下翻转颠倒的lcd数据
	for(y=0; y<h; y++)
	{
		for(x=0; x<w; x++)
		{
			lcd_buf[y*w+x] = tmp_buf[(h-1-y)*w+x];				// (二维数组) 
	     
	    }
	}
	
	// d、显示bmp图片到lcd设备上
    for(y=0;y<h;y++)
    {
        for(x=0;x<w;x++)
        {		
            p[y+lcd_y][x+lcd_x]= lcd_buf[(h-1-y)*w+x];;

        }
    }

	// 6、关闭字库、画板
	fontUnload(f);
	destroyBitmap(bm);
}
/**
  * @brief  显示字到开发板屏幕上
  * @note   None
  * @param  lcd：			显示屏的结构体指针
			f_s：			字体大小
			bmp_buf：		bmp图片路径
			f_x：			字体在bmp的x轴位置
			f_y： 			字体在bmp的y轴位置
			font_text：		需要显示的字
			f_c： 			字体的颜色
			f_lw：			字体显示在行的宽度，超过则换行，一般写0，默认不换行
			lcd_x：			画板和字形成的bmp图片，在显示屏的x轴的显示位置
			lcd_y：			画板和字形成的bmp图片，在显示屏的y轴的显示位置
  * @retval None
 */
void LCD_ShowPicFont(lcd_msg *lcd, int f_s, char *bmp_path, int f_x, int f_y, char *font_text, color f_c, int f_lw, int lcd_x, int lcd_y)
{
	// 1、打开字体	
	font *f = fontLoad("/usr/share/fonts/DroidSansFallback.ttf");

	// 2、字体大小的设置
	fontSetSize(f, f_s);

	// 3、创建一个画板（点阵图）
	bitmap *bm = createBitmapWithInit_bmp(bmp_path);
	
																// A, R, G, B，画板的颜色
	// 4、将字写到画板(点阵图)上，形成一张bmp图片
	fontPrint(f, bm, f_x, f_y, font_text, f_c, f_lw); 
										   // A, R, G, B，字的颜色
	// 5、将形成的bmp图片，显示到开发板lcd设备上
    // Lcd_ShowFontBmpToLcd(lcd, bm, lcd_x, lcd_y);	
	// a、记住最初的位置
	int (*p)[800] = (int (*)[800])lcd->p;
	
	// b、判断要刷的图片是否超过了屏幕范围
	int   w       = bm->width;
	int   h       = bm->height;
	int   n       = bm->byteperpixel;
	unsigned char *bmp_buf = bm->map;

	if(w+lcd_x>800 || h+lcd_y>480)
	{
		printf("bmp图片越界!\n");
		return;
	}
	
	// c、将获取的BGR数据(bmp的颜色数据)，转换成ARGB数据(lcd数据)
	unsigned int tmp_buf[w*h];				// ARGB数据(lcd数据)存放地(变长数组，不能赋值)
	unsigned int lcd_buf[w*h];				// ARGB数据(lcd数据)存放地(变长数组，不能赋值)
	
	int i,j,k,x,y;
	
	// 正的的lcd数据
	for(i=0; i<w*h; i++)
	{
		tmp_buf[i] = (bmp_buf[i*4+0]<<16) | (bmp_buf[i*4+1]<<8) | (bmp_buf[i*4+2]<<0) | (bmp_buf[i*4+3]<<24);
		//ARGB            R                     G                      B                 A
	}  
	
	// 上下翻转颠倒的lcd数据
	for(y=0; y<h; y++)
	{
		for(x=0; x<w; x++)
		{
			lcd_buf[y*w+x] = tmp_buf[(h-1-y)*w+x];				// (二维数组) 
	     
	    }
	}
	
	// d、显示bmp图片到lcd设备上
    for(y=0;y<h;y++)
    {
        for(x=0;x<w;x++)
        {		
            p[y+lcd_y][x+lcd_x]= lcd_buf[(h-1-y)*w+x];;

        }
    }
	
	// 6、关闭字库、画板
	fontUnload(f);
	destroyBitmap(bm);
}
>>>>>>> gec
